//
// SimpleAVRG.as
//
// Copyright (c) 2009 Nathan Barnes
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//
// SimpleAVRG - an AVR game for Whirled

package {

import com.threerings.util.Log;
import com.whirled.avrg.AVRGameControl;
import com.whirled.avrg.AVRGamePlayerEvent;
import com.whirled.avrg.AVRGameRoomEvent;
import com.whirled.net.PropertyChangedEvent;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;

public class SimpleAVRG extends Sprite
{
    public function SimpleAVRG ()
    {
        _control = new AVRGameControl(this);

        // Set up a function for drawing mobs.
        _control.local.setMobSpriteExporter(createMobSprite);

        // Set up the display.
        buildDisplay();

        // listen for an unload event
        _control.addEventListener(Event.UNLOAD, handleUnload);

        if (_control.isConnected()) {
            // Set the initial values on the score board.
            _scoreBoard.setGlobalMonsterCount( int(_control.game.props.get(SimpleAVRGConstants.GLOBAL_MONSTER_COUNT)) );
            _scoreBoard.setRoomMonsterCount( int(_control.room.props.get(SimpleAVRGConstants.ROOM_MONSTER_COUNT)) );

            // Listen for game level property changes.
            _control.game.props.addEventListener(PropertyChangedEvent.PROPERTY_CHANGED, handleGamePropertyChanged);

            // Listen for room level property changes.
            _control.room.props.addEventListener(PropertyChangedEvent.PROPERTY_CHANGED, handleRoomPropertyChanged);

            // Listen for player level property changes.
            _control.player.props.addEventListener(PropertyChangedEvent.PROPERTY_CHANGED, handlePlayerPropertyChanged);

            // Listen for mobs appearing in the room.
            _control.room.addEventListener(AVRGameRoomEvent.MOB_CONTROL_AVAILABLE, handleMobControlAvailable);

            // Listen for the player moving into a new room.
            _control.player.addEventListener(AVRGamePlayerEvent.ENTERED_ROOM, handleEnteredRoom);
        }
    }

    /**
     * Build the display.
     */
    protected function buildDisplay() :void
    {
        _scoreBoard = new ScoreBoard();
        _scoreBoard.x = 0;
        _scoreBoard.y = 0;
        addChild(_scoreBoard);

        _scoreBoard.addEventListener(ScoreBoardEvent.CATCH_MONSTER_REQUEST, handleCatchMonsterRequest);
    }

    /**
     * This builds a new mob sprite.
     */
    protected function createMobSprite (type :String) :DisplayObject
    {
        return new MonsterSprite(type);
    }

    /**
     * This is called when the player is attempting to catch a monster.
     */
    protected function handleCatchMonsterRequest (event :ScoreBoardEvent) :void
    {
        _log.info("Player attempted to catch a monster.");
        _control.agent.sendMessage(SimpleAVRGConstants.CATCH_MONSTER_REQUEST_MESSAGE);
    }
    
    /**
     * This is called when the player enters a new room, as well as when the
     * player first enters the game.
     */
    protected function handleEnteredRoom (event :AVRGamePlayerEvent) :void
    {
        _log.info("Entered room #" + _control.room.getRoomId());
        var roomCount :Object = _control.room.props.get(SimpleAVRGConstants.ROOM_MONSTER_COUNT);
        _scoreBoard.setRoomMonsterCount( int(roomCount) );
    }

    /**
     * This is called when a game property has changed.
     */
    protected function handleGamePropertyChanged (event :PropertyChangedEvent) :void
    {
        // If the global monster count has changed, update the notice board.
        if (event.name == SimpleAVRGConstants.GLOBAL_MONSTER_COUNT) {
            _scoreBoard.setGlobalMonsterCount( int(event.newValue) );
        }
    }

    /**
     * This is called when a mob enters the room.
     */
    protected function handleMobControlAvailable (event :AVRGameRoomEvent) :void
    {
        // The mob sprite exporter will already have built the sprite. Fetch it
        // by mob id and cast it into a MonsterSprite variable.
        var mobSprite :MonsterSprite = MonsterSprite(
            _control.room.getMobSubControl(event.name).getMobSprite());
        mobSprite.mobId = event.name;

        mobSprite.addEventListener(MouseEvent.CLICK, handleMobSpriteClicked);
        mobSprite.addEventListener(Event.UNLOAD, function (event :Event) :void {
            removeEventListener(MouseEvent.CLICK, handleMobSpriteClicked);
        });
    }

    /**
     * This is called when a mob sprite has been clicked.
     */
    protected function handleMobSpriteClicked(event :MouseEvent) :void
    {
        if (event.target is MonsterSprite) {
            var monsterSprite :MonsterSprite = MonsterSprite(event.target);
            _control.agent.sendMessage(SimpleAVRGConstants.CATCH_MONSTER_REQUEST_MESSAGE, monsterSprite.mobId);
        }
    }

    /**
     * This is called when a player property has changed.
     */
    protected function handlePlayerPropertyChanged (event :PropertyChangedEvent) :void
    {
        // If the player's basket monster count has changed, update the notice board.
        if (event.name == SimpleAVRGConstants.BASKET_MONSTER_COUNT) {
            _scoreBoard.setBasketMonsterCount( int(event.newValue) );
        }
    }

    /**
     * This is called when a room property has changed.
     */
    protected function handleRoomPropertyChanged (event :PropertyChangedEvent) :void
    {
        // If the room monster count has changed, update the notice board.
        if (event.name == SimpleAVRGConstants.ROOM_MONSTER_COUNT) {
            _scoreBoard.setRoomMonsterCount( int(event.newValue ));
        }
    }

    /**
     * This is called when your game is unloaded.
     */
    protected function handleUnload (event :Event) :void
    {
        // stop any sounds, clean up any resources that need it.  This specifically includes 
        // unregistering listeners to any events - especially Event.ENTER_FRAME
        if (_control != null) {
            _control.game.props.removeEventListener(PropertyChangedEvent.PROPERTY_CHANGED, handleGamePropertyChanged);
            _control.room.props.removeEventListener(PropertyChangedEvent.PROPERTY_CHANGED, handleRoomPropertyChanged);
            _control.player.removeEventListener(AVRGamePlayerEvent.ENTERED_ROOM, handleEnteredRoom);
        }
    }

    protected var _control :AVRGameControl;
    protected var _log :Log = Log.getLog(SimpleAVRG);
    protected var _scoreBoard :ScoreBoard;
}
}
